package po

import (
	"database/sql/driver"
	"encoding/json"
	"fmt"
	"github.com/duke-git/lancet/v2/convertor"
	"manager/errors"
	"strconv"
)

// Array 泛型数组，以jsonb的形式存储在数据库
type Array[T string | int32 | int8 | Point | Location | GpsLocation] []T

// Scan 实现 sql.Scanner 接口，Scan 将 value 扫描至 Jsonb
func (a *Array[T]) Scan(value interface{}) error {
	bytes, ok := value.([]byte)
	if !ok {
		return errors.New(fmt.Sprint("Failed to scan Array value:", value))
	}
	if len(bytes) > 0 {
		return json.Unmarshal(bytes, a)
	}
	*a = make([]T, 0)
	return nil
}

// Value 实现 driver.Valuer 接口，Value 返回 json value
func (a Array[T]) Value() (driver.Value, error) {
	if a == nil {
		return "[]", nil
	}
	return convertor.ToString(a), nil
}

// Location 位置
type Location struct {
	Lat float64 `json:"lat"`
	Lng float64 `json:"lng"`
}

// Point 坐标
type Point struct {
	X float64 `json:"lng"` // 经度
	Y float64 `json:"lat"` // 维度
}

func (p Point) Value() (driver.Value, error) {
	out := []byte{'('}
	out = strconv.AppendFloat(out, p.X, 'f', -1, 64)
	out = append(out, ',')
	out = strconv.AppendFloat(out, p.Y, 'f', -1, 64)
	out = append(out, ')')
	return out, nil
}

func (p Point) String() string {
	return fmt.Sprintf("(%v, %v)", p.X, p.Y)
}
func (p *Point) Scan(src interface{}) (err error) {
	var data []byte
	switch src := src.(type) {
	case []byte:
		data = src
	case string:
		data = []byte(src)
	case nil:
		return nil
	default:
		return errors.New("(*Point).Scan: unsupported data type")
	}
	if len(data) == 0 {
		return nil
	}
	data = data[1 : len(data)-1] // drop the surrounding parentheses
	for i := 0; i < len(data); i++ {
		if data[i] == ',' {
			if p.X, err = strconv.ParseFloat(string(data[:i]), 64); err != nil {
				return err
			}
			if p.Y, err = strconv.ParseFloat(string(data[i+1:]), 64); err != nil {
				return err
			}
			break
		}
	}
	return nil
}

// EbikeSet 车辆设置
type EbikeSet struct {
	PowerWarn            int   `json:"power_warn"`            // 电量提醒
	PowerValue           int   `json:"power_value"`           // 设置提醒值1~99
	LeaveLock            int   `json:"leave_lock"`            // 离车自动锁车 0 开启 1关闭
	LeaveCountdown       int   `json:"leave_countdown"`       // 锁车倒计时
	OpenLock             int   `json:"open_lock"`             // 无感开锁
	OpenLockDistance     int   `json:"open_lock_distance"`    // 开锁距离
	HitchsUp             int   `json:"hitchs_up"`             // 故障上报
	Alarm                int   `json:"alarm"`                 // 被盗告警 0 推送 1 忽略
	ElectronicFence      int   `json:"electronic_fence"`      // 电子围栏 0 开启，1 关闭
	FenceCenter          Point `json:"fence_center"`          // 围栏中心点
	FenceRadius          int   `json:"fence_radius"`          // 围栏半径
	VibrationSensitivity int   `json:"vibration_sensitivity"` // 报警器震动灵敏度（震动），等级1~3，值越大越灵敏。
}

func (e *EbikeSet) Value() (driver.Value, error) {
	out, err := json.Marshal(e)
	return out, err
}

func (e *EbikeSet) Scan(src interface{}) (err error) {
	var data []byte
	switch src := src.(type) {
	case []byte:
		data = src
	case string:
		data = []byte(src)
	case nil:
		return nil
	default:
		return errors.New("(*Point).Scan: unsupported data type")
	}
	if len(data) == 0 {
		return nil
	}
	return json.Unmarshal(data, e)
}

// MsgSet 防盗设置
type MsgSet struct {
	StealAlarm    int `json:"steal_alarm"`    // 防盗告警
	Hitchs        int `json:"hitchs"`         // 故障
	Shake         int `json:"shake"`          // 振动
	BlackOut      int `json:"black_out"`      // 断电
	ChargeMonitor int `json:"charge_monitor"` // 充电检测
	Handrail      int `json:"handrail"`       // 电子围栏
}

func (m *MsgSet) Value() (driver.Value, error) {
	out, err := json.Marshal(m)
	return out, err
}

func (m *MsgSet) Scan(src interface{}) (err error) {
	var data []byte
	switch src := src.(type) {
	case []byte:
		data = src
	case string:
		data = []byte(src)
	case nil:
		return nil
	default:
		return errors.New("(*Point).Scan: unsupported data type")
	}
	if len(data) == 0 {
		return nil
	}
	return json.Unmarshal(data, m)
}

type GpsLocation struct {
	Time     int32   `json:"t"`
	Lat      float64 `json:"lat"`
	Lng      float64 `json:"lng"`
	GpsSpeed float64 `json:"s"` // 速度
	Bearing  float64 `json:"b"` // 偏向角
}
